#ifndef DEF_H
#define DEF_H

#include <string>
#include <vector>
#include <set>
#include <stdint.h>
#include <ext/hash_set>

using namespace __gnu_cxx;
using namespace std;

// nodes movetype
typedef enum {terminal, terminal_NI, nodes_moveable} NODES_MOVE_TYPE;

// pl movetype
typedef enum {FIXED, FIXED_NI, pl_moveable} PL_MOVE_TYPE;

// movetype
typedef enum {N, S} ORIENTATION;

typedef enum {I, O} NET_DIRECTION;

// struct for shape
typedef struct {
	int id;
	int ll_xcoord;
	int ll_ycoord;
	int width;
	int height;
} SHAPE;
	

// Abstract class for nodes
class Node{
	public:
		// COnstructor
		Node(){
			// If there is no movetype, then the node is movable
			nodes_movetype = nodes_moveable;
			pl_movetype = pl_moveable;
			orientation = N;
			layer_id = -1;
			isBlockage = false;
			ranking = 0;
		}
		
		// Destructor
		~Node(){
			shapes.clear();
		}
		
		void setCenter(void){
			centerX = ll_xcoord + width/2 + (width%2);
			centerY = ll_ycoord + height/2 + (height%2);
		}
		
		// from file .nodes
		string name;
		int width;
		int height;
		int centerX, centerY;
		NODES_MOVE_TYPE nodes_movetype;
		
		// from file *.pl
		int ll_xcoord;
		int ll_ycoord;
		ORIENTATION orientation;
		PL_MOVE_TYPE pl_movetype;
		
		//from file *.shapes
		vector<SHAPE> shapes;
		
		//from file *.route
		bool isBlockage;
		int layer_id;
		vector<int> layer_list;
		
		// from analysis
		int ranking;
		
};

ostream &operator<<(ostream &stream, Node *node)
{
  stream << node->name<<endl;
  stream << "width:"<<node->width<<"\theight:"<<node->height<<"\tnodes_movetype:"<<node->nodes_movetype<<endl;
  stream << "ll_xcoord:"<<node->ll_xcoord<<"\tll_ycoord:"<<node->ll_ycoord<<
  			"\torientation:"<<node->orientation<<"\tpl_movetype:"<<node->pl_movetype<<endl;
  if(node->shapes.size())
  	for(uint32_t i=0; i<node->shapes.size(); ++i)
  		stream << "shape id:"<<node->shapes[i].id<<"\tll_xcoord:"<<node->shapes[i].ll_ycoord<<"\twidth:"<< 
  				   node->shapes[i].width <<"\theight:"<<node->shapes[i].height<<endl;
  stream << "isBlockage:"<<node->isBlockage<<endl;
  return stream; 
}
   
   
struct offset{
	float x;
	float y;
};

struct point{
	int x;
	int y;
	int z;
};

class PCoarseNet {
	public:
		string name;
		vector<Node*> terminals;
		vector<NET_DIRECTION> directions;
		vector<offset> offsets;
		vector<point> points;
		
		// Destructor
		~PCoarseNet(){
			terminals.clear();
			directions.clear();
			offsets.clear();
			points.clear();
		}
};

class   Box
{
public:
        uint32_t        llx, lly;
        uint32_t        dx, dy;
        bool            defined;

        Box (): defined(false) {}
        void    dfnBox ( uint32_t llX, uint32_t llY, uint32_t dX, uint32_t dY )
        {
                if ( dX < 0 || dY < 0 )
                        exit (0);
                llx = llX;      lly = llY;
                dx = dX;        dy = dY;
                defined = true;
        }
        void    prtBox ()
        {
                if ( !defined )
                        exit (0);
        }
        bool    containPoint ( const point p )
        {
                if ( !defined )
                        exit (0);
                uint32_t hrx = llx+dx;
                uint32_t hry = lly+dy;
//                printf ( "\t(%d, %d, %d) : ", p.x, p.y, p.z );
                return ( p.x>=llx && p.x<=hrx && p.y>=lly && p.y<=hry );
        }
        bool    containNet ( PCoarseNet *ptNet )
        {
                vector<point>::iterator it;
                for ( it = ptNet->points.begin(); it != ptNet->points.end(); ++it )
                        if ( !containPoint(*it) )
                                return  false;
                return  true;
        }
};


struct Blockage{
	point p1;
	point p2;
	int cap;
};
		
// private hash finctions
struct hash_node 
{ 
    size_t operator()( const Node *t) const
    { 
         hash<const char*> H; 
        return H( t->name.c_str() ); 
    } 
}; 

// private equal function
struct eq_node 
{ 
    bool operator()(const Node *t1, const Node *t2) const { 
        return ( t1->name == t2->name ); 
    } 
}; 
	
	// nodes set and iterator
	typedef hash_set<Node*, hash_node, eq_node> NODE_SET;
	typedef hash_set<Node*, hash_node, eq_node>::const_iterator NODE_ITERATOR;
		
	#define LINESIZE 1024;
#endif
